#include "VanishingPoint.h"
#include "Segment.h"
#include "Point2f.h"

#include "ofxThread.h"

#include "ofMath.h"
#include "ofImage.h"

#include "ofxOpenCv.h"
#include "cv.h"

#include <vector>
#include <algorithm>
#include <string>
#include <list>


#ifndef __ABLIEFERN_VANISHING_POINT_ORACLE
#define __ABLIEFERN_VANISHING_POINT_ORACLE

#define RGB_CANNY


namespace abliefern {
	
	class VanishingPointOracle : public ofxThread {
		
	public:
		VanishingPointOracle(std::string theFileName, std::string thePathName);
		~VanishingPointOracle();
		
		
		void draw();
		void update();

		
		bool hasFinishedCompletely();
		bool hasFinishedLoading();
		
		/* Threading */
		void start();
		void kill();
		void threadedFunction();
		
		
		/* User choices */
		void acceptVanishingPoint();
		void denyVanishingPoint();
		void ignoreVanishingPoint();
		void finishDetection();
		
		
		/* Dimensions */
		int getWidth();
		int getHeight();
		
		
		void zoomIn();
		void zoomOut();
		
		std::string getFileName();
		
		
		std::vector<VanishingPoint> getVanishingPoints();
		
		
		
		/* Results */
		
		/* Helpers */
		static int randomInt(int theMaximum);
		
		
		
	private:
		bool _myIsInited;
		bool _myIsFinishedCompletely;
		bool _myHasProposal;
		bool _myHasNoMoreProposals;
		
		float _myScale;
		
		VanishingPoint  _myVPProposal;
		
		std::vector<Segment> _myLines;
		std::vector<Segment*> _myRemainingLines;

		
		std::vector<VanishingPoint> _mySelection;
		
		std::vector<Segment*> _mySupportLines;
		std::vector<VanishingPoint> _myIgnores;
		
		
		/* File location */
		std::string _myFileName;
		std::string _myPathName;

		
		/* Parameters */
		int _myLineThreshold;
		int _myLineThresholdSquared;
		
		
		/* Images */
		ofImage _myOriginalImage;
		ofImage _myDisplayImage;
		
		/* Process */
		void loadImage();
		void processImage();
		void filterLines();
		
		
		/* VP */
		void proposeNewVanishingPoint();
		void removeCurrentSupportLines();

		
			
		
		bool filterLine(double theTheta);		
		bool getVanishingPoint(int theIterations, std::vector<abliefern::Segment*>* theLines,  abliefern::Point2f* theBestPoint, std::vector<abliefern::Segment*>* theSupports, std::vector<abliefern::Point2f*>* theIgnores);



	};
	
}

#endif